/**
 * 并发控制工具类
 * 用于控制并发请求数量，避免过多并发导致浏览器卡顿或服务器压力过大
 */

/**
 * 并发池配置
 */
export interface ConcurrentPoolConfig {
  maxConcurrent?: number // 最大并发数，默认8
  retryTimes?: number // 失败重试次数，默认2
  retryDelay?: number // 重试延迟（毫秒），默认1000
}

/**
 * 任务项
 */
export interface Task<T> {
  id: string | number
  executor: () => Promise<T>
}

/**
 * 任务结果
 */
export interface TaskResult<T> {
  id: string | number
  success: boolean
  data?: T
  error?: Error
}

/**
 * 并发池类
 */
export class ConcurrentPool<T> {
  private maxConcurrent: number
  private retryTimes: number
  private retryDelay: number
  private tasks: Task<T>[] = []
  private results: TaskResult<T>[] = []
  private running = 0
  private resolve!: (value: TaskResult<T>[]) => void
  private onProgress?: (completed: number, total: number) => void

  constructor(config: ConcurrentPoolConfig = {}) {
    this.maxConcurrent = config.maxConcurrent || 8
    this.retryTimes = config.retryTimes || 2
    this.retryDelay = config.retryDelay || 1000
  }

  /**
   * 添加任务
   */
  addTask(task: Task<T>): void {
    this.tasks.push(task)
  }

  /**
   * 批量添加任务
   */
  addTasks(tasks: Task<T>[]): void {
    this.tasks.push(...tasks)
  }

  /**
   * 设置进度回调
   */
  setProgressCallback(callback: (completed: number, total: number) => void): void {
    this.onProgress = callback
  }

  /**
   * 执行所有任务
   */
  async run(): Promise<TaskResult<T>[]> {
    if (this.tasks.length === 0) {
      return []
    }

    return new Promise((resolve) => {
      this.resolve = resolve
      this.results = []
      this.running = 0

      // 启动初始并发任务
      for (let i = 0; i < Math.min(this.maxConcurrent, this.tasks.length); i++) {
        this.runNext()
      }
    })
  }

  /**
   * 运行下一个任务
   */
  private runNext(): void {
    if (this.tasks.length === 0) {
      // 所有任务都已启动
      if (this.running === 0) {
        // 所有任务都已完成
        this.resolve(this.results)
      }
      return
    }

    const task = this.tasks.shift()!
    this.running++

    this.executeTask(task)
      .then((result) => {
        this.results.push(result)
        this.running--
        
        // 通知进度
        if (this.onProgress) {
          this.onProgress(this.results.length, this.results.length + this.tasks.length + this.running)
        }

        // 继续执行下一个任务
        this.runNext()
      })
      .catch((error) => {
        console.error('Task execution failed:', error)
        this.running--
        this.runNext()
      })
  }

  /**
   * 执行单个任务（带重试）
   */
  private async executeTask(task: Task<T>, attempt = 0): Promise<TaskResult<T>> {
    try {
      const data = await task.executor()
      return {
        id: task.id,
        success: true,
        data
      }
    } catch (error) {
      if (attempt < this.retryTimes) {
        // 等待后重试
        await this.delay(this.retryDelay)
        return this.executeTask(task, attempt + 1)
      }
      
      // 重试失败
      return {
        id: task.id,
        success: false,
        error: error as Error
      }
    }
  }

  /**
   * 延迟函数
   */
  private delay(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms))
  }
}

/**
 * 简化的并发执行函数
 */
export async function runConcurrent<T>(
  tasks: Task<T>[],
  config: ConcurrentPoolConfig = {},
  onProgress?: (completed: number, total: number) => void
): Promise<TaskResult<T>[]> {
  const pool = new ConcurrentPool<T>(config)
  pool.addTasks(tasks)
  
  if (onProgress) {
    pool.setProgressCallback(onProgress)
  }
  
  return pool.run()
}

/**
 * 批量并发执行（简化版，使用Promise.all分批）
 */
export async function batchConcurrent<T>(
  items: any[],
  executor: (item: any, index: number) => Promise<T>,
  batchSize = 8
): Promise<T[]> {
  const results: T[] = []
  
  for (let i = 0; i < items.length; i += batchSize) {
    const batch = items.slice(i, i + batchSize)
    const batchResults = await Promise.all(
      batch.map((item, idx) => executor(item, i + idx))
    )
    results.push(...batchResults)
  }
  
  return results
}

/**
 * 并发执行函数数组（带限制）
 */
export async function limitedConcurrent<T>(
  executors: Array<() => Promise<T>>,
  limit = 8
): Promise<T[]> {
  const results: T[] = new Array(executors.length)
  const executing: Promise<void>[] = []

  for (let i = 0; i < executors.length; i++) {
    const executor = executors[i]
    const index = i

    const promise = Promise.resolve()
      .then(() => executor())
      .then((result) => {
        results[index] = result
      })

    executing.push(promise)

    if (executing.length >= limit) {
      await Promise.race(executing)
      // 移除已完成的promise
      const completedIndex = executing.findIndex(p => 
        Promise.race([p.then(() => true), Promise.resolve(false)])
      )
      if (completedIndex !== -1) {
        executing.splice(completedIndex, 1)
      }
    }
  }

  await Promise.all(executing)
  return results
}

